#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <glob.h>
#include <stdlib.h>

#include "queries.h"

#include <rasqal/rasqal.h>

typedef struct {
  raptor_statement * this;
  void * next;
} stmt_list;

stmt_list * known_stmts;

raptor_world *r_world;

int already_known(raptor_statement *rs) {
  stmt_list * list = known_stmts;
  while(list->this != NULL) {
    raptor_statement *o = list->this;
    if( (o->subject_type == rs->subject_type) &&
	(o->predicate_type == rs->predicate_type) &&
	(o->object_type == rs->object_type) &&
	(!strcmp(o->subject,rs->subject)) &&
	(!strcmp(o->predicate,rs->predicate)) &&
	(!strcmp(o->object,rs->object)) ) {
      return 1;
    }
    list = list->next;
  }
  return 0;
}

void add_stmt(raptor_statement *rs) {
  stmt_list * newl = malloc(sizeof(stmt_list));
  newl->this = malloc(sizeof(raptor_statement));
  newl->this->subject_type = rs->subject_type;
  newl->this->predicate_type = rs->predicate_type;
  newl->this->object_type = rs->object_type;
  newl->this->subject = malloc(sizeof(char) * (1 + strlen(rs->subject)));
  strcpy(newl->this->subject, rs->subject);
  newl->this->predicate = malloc(sizeof(char) * (1 + strlen(rs->predicate)));
  strcpy(newl->this->predicate, rs->predicate);
  newl->this->object = malloc(sizeof(char) * (1 + strlen(rs->object)));
  strcpy(newl->this->object, rs->object);

  newl->next = known_stmts;
  known_stmts = newl;
}

int execute_query(rasqal_world *world, const unsigned char* query,
		  raptor_uri* sources[], int n_sources) {
  const char *ql_name = "sparql";
  char *ql_uri = NULL;
  raptor_uri* base_uri = NULL;
  rasqal_query *rq;
  rasqal_query_results *results;

  rq = rasqal_new_query(world, (const char*) ql_name, 
			(const unsigned char*) ql_uri);
  
  int i;
  for(i=0;i<n_sources;i++) {
    rasqal_query_add_data_graph(rq, sources[i], NULL, 
				RASQAL_DATA_GRAPH_BACKGROUND);
  }

  rasqal_query_prepare(rq, (const unsigned char*) query, base_uri);

  results = rasqal_query_execute(rq);

  raptor_serializer* serializer = NULL;
  const char *serializer_syntax_name = "ntriples";
  rasqal_query_results_formatter* results_formatter = NULL;

  serializer = raptor_new_serializer(serializer_syntax_name);

  FILE *tmpout = fopen("tmp.n3","a");
  raptor_serialize_start_to_file_handle(serializer, base_uri, tmpout);

  int triple_count = 0;
  while(1) {
    raptor_statement *rs = rasqal_query_results_get_triple(results);
    if(!rs)
      break;
    
    if(!already_known(rs)) {
      
      add_stmt(rs);

      raptor_serialize_statement(serializer, rs);
      triple_count++;

    }

    if(rasqal_query_results_next_triple(results))
      break;
  }

  raptor_serialize_end(serializer);
  raptor_free_serializer(serializer);

  fclose(tmpout);
  rasqal_free_query(rq); 

  return triple_count; 
}


int main(int argc, char *argv[]) {
  known_stmts = malloc(sizeof(stmt_list));
  known_stmts->this = NULL;
  known_stmts->next = NULL;

  rasqal_world *world;

/*   glob_t files; */
/*   int rc = glob("*.sparql",0,NULL,&files); */
/*   printf("Glob: %i\n", rc); */
/*   int n_queries = files.gl_pathc; */
/*   unsigned char** queries = (unsigned char**) malloc(n_queries * sizeof(unsigned char*)); */
/*   int l; */
/*   for(l=0;l<files.gl_pathc;l++) { */
/*     FILE* qin = fopen(files.gl_pathv[l]); */
/*     queries[l] = (unsigned char*) malloc(sizeof(unsigned char) * (strlen(files.gl_pathv[l]) + 1)); */
/*     queries[l][strlen(files.gl_pathv[l])] = '\0'; */
/*     strncpy(queries[l],files.gl_pathv[l],strlen(files.gl_pathv[l])); */
/*   } */
/*   globfree(&files); */
  int l;
  for(l=0;l<n_queries;l++) {
    printf("Query %i: %s\n", l, queries[l]);
  }

  world = rasqal_new_world();
  rasqal_world_open(world);
  r_world = rasqal_world_get_raptor(world);

  int i;
  int n_sources = argc + 1;
  raptor_uri** sources = (raptor_uri**) malloc(n_sources * sizeof(raptor_uri*));
  for(i=1;i<argc;i++) {
    const unsigned char* uri_string = raptor_uri_filename_to_uri_string(argv[i]);
    raptor_uri* source_uri = raptor_new_uri((const unsigned char*) uri_string);
    sources[i] = source_uri;
  }

  unsigned char* tmp_uri_str;
  tmp_uri_str = raptor_uri_filename_to_uri_string("tmp.n3");
  sources[0] = raptor_new_uri((const unsigned char *) tmp_uri_str);
  sources[argc] = raptor_new_uri(raptor_uri_filename_to_uri_string("rdf-schema.rdf"));

  int added_triples;
  do {
    added_triples = 0;
    for(i=0;i<n_queries;i++)
      added_triples += execute_query(world, queries[i], sources, n_sources);
    printf("Added %i triples.\n", added_triples);
  } while(added_triples > 0);



  for(i=0;i<n_sources;i++) {
    raptor_free_uri(sources[i]);
  }
  free(sources);

  rasqal_free_world(world);

  // load data graphs
  // execute queries until no new triples are added
  // write them out
}
